package com.quanyan.weichat.api;


import com.alibaba.fastjson.JSON;
import com.quanyan.common.utils.*;
import com.quanyan.weichat.common.Configure;
import com.quanyan.weichat.common.RandomStringGenerator;
import com.quanyan.weichat.common.Signature;
import com.quanyan.weichat.common.Util;
import com.quanyan.weichat.protocol.closeorder_protocal.CloseOrdeReqData;
import com.quanyan.weichat.protocol.templatemessage_protocal.TemplateMessageProtocal;
import com.quanyan.weichat.protocol.transfer_fund_protocal.TransferFundReqData;
import com.quanyan.weichat.protocol.transfer_fund_protocal.TransferFundResData;
import com.quanyan.weichat.util.HttpClientUtil4Weichat;
import com.quanyan.weichat.util.HttpClientUtils;
import com.quanyan.weichat.util.HttpsClientUtil;
import com.quanyan.weichat.vo.OpenIdAndSessionVo;
import com.quanyan.weichat.vo.WxUserInfo;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import net.sf.json.JSONObject;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.http.HttpMethod;
import org.springframework.util.StringUtils;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;

/**
 * Created by zijun.song on 2015/7/2.
 */
public class WeichatServiceApi {

    public static final String ACCESS_TOKEN = "access_token";

    public static final String EXPIRES_IN = "expires_in";

    public static final String REFRESH_TOKEN = "refresh_token";

    public static final String OPEN_ID = "openid";

    public static final String UNION_ID = "unionid";

    public static final String SCOPE = "scope";

    private Log log = LogFactory.getLog(WeichatServiceApi.class);

    public Map<String, String> getQrcodeTicket(String globalAccessToken) {
        String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + globalAccessToken;
        Map<String, String> map = new HashMap<String, String>();
        map.put("result", "false");
        try {
            Random random = new Random();
            String json = "{\"expire_seconds\": 604800, \"action_name\": \"QR_SCENE\", \"action_info\": {\"scene\": {\"scene_id\": 123}}}";
            Map result = stringToMap(HttpClientUtils.postJson(url, json));
            if (result != null && result.size() > 0) {
                String ticket = result.get("ticket").toString();
                Long expire_seconds = Long.valueOf(result.get("expire_seconds").toString());
                String qrcodeUrl = result.get("url").toString();
                if (!StringUtils.isEmpty(ticket)) {
                    //获取成功!
                    map.put("refresh_time", System.currentTimeMillis() + ""); //刷新时间
                    map.put("ticket", ticket); //token
                    map.put("expire_seconds", expire_seconds.toString());//过期时间, 秒
                    map.put("result", "true");
                    map.put("url", "qrcodeUrl");
                    log.warn("获取二维码ticket成功==>" + result);
                } else {
                    log.warn("获取二维码ticket成功==>" + result);
                }
            }
        } catch (Exception e) {
            log.warn("获取二维码ticket成功==>" + e.getMessage());
        }
        return map;
    }

    public Map<String, String> refreshToken(String appId, String securityKey) {
        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + securityKey;
        Map<String, String> map = new HashMap<String, String>();
        map.put("result", "false");
        try {
            String result = HttpClientUtils.get(url);
            if (!org.codehaus.plexus.util.StringUtils.isBlank(result)) {
                com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(result);
                String access_token = jsonObject.getString("access_token");
                Long expires_in = jsonObject.getLong("expires_in");
                if (!StringUtils.isEmpty(access_token)) {
                    //获取成功!
                    map.put("refresh_time", System.currentTimeMillis() + ""); //刷新时间
                    map.put("access_token", access_token); //token
                    map.put("expires_in", expires_in.toString());//过期时间, 秒
                    map.put("result", "true");
                    log.warn("appId=" + appId + ",获取AccessToken成功==>" + result);
                } else {
                    log.warn("appId=" + appId + ",请求结果：" + result + "获取AccessToken失败==>" + result);
                }
            }
        } catch (Exception e) {
            log.warn("appId=" + appId + ",获取AccessToken失败==>" + ObjectUtil.getFullStackTraceToString(e));
        }
        return map;
    }

    public Map<String, String> refreshJsApiTiket(String globalAccessToken) {
        String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + globalAccessToken + "&type=jsapi";
        Map<String, String> map = new HashMap<String, String>();
        map.put("result", "false");
        try {
            String result = HttpClientUtils.get(url);
            if (!StringUtils.isEmpty(result)) {
                com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(result);
                String ticket = jsonObject.getString("ticket");
                Long expires_in = jsonObject.getLong("expires_in");
                if (!StringUtils.isEmpty(ticket)) {
                    //获取成功!
                    map.put("refresh_time", System.currentTimeMillis() + ""); //刷新时间
                    map.put("ticket", ticket); //token
                    map.put("expires_in", expires_in.toString());//过期时间, 秒
                    map.put("result", "true");
                    log.warn("获取ticket成功==>" + result);
                } else {
                    log.warn("获取ticket失败==>" + result);
                }
            }
        } catch (Exception e) {
            log.warn("获取ticket失败==>" + ObjectUtil.getFullStackTraceToString(e));
        }
        return map;

    }

    /**
     * 获取每个用户的openId key
     *
     * @param openId
     * @return
     */
    public static String getOpenIdKey(String openId) {
        return OPEN_ID + "." + openId;
    }

    /**
     * 获取用户基本信息.
     *
     * @param openId
     * @return
     */
    public WxUserInfo getUserInfos(String openId, String globalAccessToken) {
        String url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + globalAccessToken + "&openid=" + openId + "&lang=zh_CN";
        String responseStr = HttpUtils.sendWebRequestByGet(null, url, "UTF-8");
        WxUserInfo wxUserInfo = new WxUserInfo();
        if (StringUtil.isBlankOrNull(responseStr)) {
            return wxUserInfo;
        }
        System.out.println(responseStr);
        wxUserInfo = GsonUtils.jsonStrToEntity(responseStr, WxUserInfo.class);
        return wxUserInfo;
    }


    /**
     * 获取用户OpenId
     * 微信文档：https://mp.weixin.qq.com/wiki/4/9ac2e7b1f1d22e9e57260f6553822520.html
     * @param code
     * @return
     */
    public Map<String, String> getUserOpenId(String appId, String securityKey, String code) {
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + appId + "&secret=" + securityKey + "&code=" + code + "&grant_type=authorization_code";
        return getResultToMap(url);
    }

    /**
     * 获取用户基本信息.
     *
     * @param openId
     * @return
     */
    public Map<String, String> getUserInfo(String openId, String globalAccessToken) {
        String url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + globalAccessToken + "&openid=" + openId + "&lang=zh_CN";
        return getResultToMap(url);
    }

    /**
     * 通过页面权鉴进入时,获取用户基本信息.
     *
     * @param openId
     * @return
     */
    public Map<String, String> getSNSUserInfo(String openId, String userAccessToken) {
        String url = "https://api.weixin.qq.com/sns/userinfo?access_token=" + userAccessToken + "&openid=" + openId + "&lang=zh_CN";
        return getResultToMap(url);
    }


    public Map<String,String> payOrderQuery(String xml)throws Exception{
        String url = "https://api.mch.weixin.qq.com/pay/orderquery";
        String result = HttpClientUtils.postXml(url, xml,null,null);
        Util.log(result);
        return ObjectUtil.convertXmlToMap(result);
    }


    /**
     * 统一下单
     *
     * @param xml
     * @return
     * @throws Exception
     */
    public Map<String, String> userPrePay(String xml) throws Exception {
        log.warn("统一下单请求xml:"+xml);
        String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        String result = HttpClientUtils.postXml(url, xml,null,null);
        Util.log(result);
        return ObjectUtil.convertXmlToMap(result);
    }

    public Map<String, String> weichatScanPay(String xml) throws Exception {
        log.warn("微信扫描枪支付xml:"+xml);
        String url = "https://api.mch.weixin.qq.com/pay/micropay";
        String result = HttpClientUtils.postXml(url, xml,2000,2000);
        Util.log(result);
        return ObjectUtil.convertXmlToMap(result);
    }

    public Map<String,String> closeScanOrder(CloseOrdeReqData params) {
        String url = "https://api.mch.weixin.qq.com/secapi/pay/reverse";
        String requestXml = ObjectUtil.objectToXMLString(params);
        log.warn("微信扫描枪订单关闭请求xml:" + requestXml);
        String responseStr = HttpUtils.sendWebRequest(url, HttpMethod.POST, null, requestXml, null, "UTF-8", null, null);
        Util.log("请求结果为：" + responseStr);
        return ObjectUtil.convertXmlToMap(responseStr);
    }

    public Map<String, String> closeOrder(CloseOrdeReqData data) {
        String url = "https://api.mch.weixin.qq.com/pay/closeorder";
        String requestXml = ObjectUtil.objectToXMLString(data);
        log.warn("关闭订单请求xml:" + requestXml);
        String responseStr = HttpUtils.sendWebRequest(url, HttpMethod.POST, null, requestXml, null, "UTF-8", null, null);
        Util.log("请求结果为：" + responseStr);
        return ObjectUtil.convertXmlToMap(responseStr);
    }

    /**
     * 长连接转换为段连接
     *
     * @param longURL
     * @return
     * @throws Exception
     */
    public String long2ShortURL(String longURL, String globalAccessToken, String certLocalPath, String certPassword) throws Exception {
        String url = "https://api.weixin.qq.com/cgi-bin/shorturl?access_token=" + globalAccessToken;
        JSONObject object = new JSONObject();
        object.put("action", "long2short");//"{\"\":\"\",\"\":\"http://wap.koudaitong.com/v2/showcase/goods?alias=128wi9shh&spm=h56083&redirect_count=1\"}"
        object.put("long_url", longURL);
        HttpsClientUtil httpsClientUtil = new HttpsClientUtil(certLocalPath, certPassword);
        String result = httpsClientUtil.sendPost(url, object.toString(), "text/json");
        Util.log(result);
        return JSONObject.fromObject(result).getString("short_url");
    }


    /**
     * 长连接转换为段连接
     *
     * @param longURL
     * @return
     * @throws Exception
     */
    public String long2ShortURL(String longURL, String globalAccessToken, InputStream inputStream, String certPassword) throws Exception {
        String url = "https://api.weixin.qq.com/cgi-bin/shorturl?access_token=" + globalAccessToken;
        JSONObject object = new JSONObject();
        object.put("action", "long2short");//"{\"\":\"\",\"\":\"http://wap.koudaitong.com/v2/showcase/goods?alias=128wi9shh&spm=h56083&redirect_count=1\"}"
        object.put("long_url", longURL);
        HttpsClientUtil httpsClientUtil = new HttpsClientUtil(inputStream, certPassword);
        String result = httpsClientUtil.sendPost(url, object.toString(), "text/json");
        Util.log(result);
        return JSONObject.fromObject(result).getString("short_url");
    }

    /**
     *  获取用户网页授权下的用户信息。参见文档：https://mp.weixin.qq.com/wiki/4/9ac2e7b1f1d22e9e57260f6553822520.html
     * @param accessToken  此access_token与基础支持的access_token不同
     * @param openId
     */
    public WxUserInfo getAccreditUserInfo(String accessToken, String openId) {
        String url = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN";
        url = String.format(url, accessToken, openId);
        String responseStr = HttpUtils.sendWebRequestByGet(null, url, "UTF-8");
        WxUserInfo wxUserInfo = new WxUserInfo();
        if (StringUtil.isNotBlank(responseStr)) {
            wxUserInfo = GsonUtils.jsonStrToEntity(responseStr, WxUserInfo.class);
        }
        return wxUserInfo;
    }

    /**
     * 用户退款
     *
     * @param xml
     * @return
     * @throws Exception
     */
    public Map<String, String> userRefund(String xml, String certLocalPath, String certPassword) throws Exception {
        String url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
        Util.log(xml);
        HttpsClientUtil httpsClientUtil = new HttpsClientUtil(certLocalPath, certPassword);
        String result = httpsClientUtil.sendPost(url, xml);
        Util.log(result);
        return ObjectUtil.convertXmlToMap(result);
    }

    /**
     * 用户退款
     *
     * @param xml
     * @return
     * @throws Exception
     */
    public Map<String, String> userRefund(String xml, InputStream certData, String certPassword) throws Exception {
        String url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
        Util.log(xml);
        HttpsClientUtil httpsClientUtil = new HttpsClientUtil(certData, certPassword);
        String result = httpsClientUtil.sendPost(url, xml);
        Util.log(result);
        return ObjectUtil.convertXmlToMap(result);
    }

    /**
     * 用户退款状态查询
     *
     * @param xml
     * @return
     * @throws Exception
     */
    public Map<String, String> userRefundQuery(String xml) throws Exception {
        String url = "https://api.mch.weixin.qq.com/pay/refundquery";
        Util.log(xml);
        String result = HttpClientUtils.postXml(url, xml,null,null);
        Util.log(result);
        return ObjectUtil.convertXmlToMap(result);
    }

    /**
     * 企业微信转账给某商户下面的用户
     * @param transferFundReqData
     * @return
     */
    public TransferFundResData transferFund(TransferFundReqData transferFundReqData){
        String reqXml = transferFundReqData.toXml();
        TransferFundResData resData = new TransferFundResData();
        try {
            HttpClientUtil4Weichat weichatClient = new HttpClientUtil4Weichat();
            weichatClient.setSslKeyStore(transferFundReqData.getMchid());
            weichatClient.setSslCertificate(transferFundReqData.getSslCertificate());

            String result =  weichatClient.postXml2Wx(Configure.TRANSFER_API, reqXml);
            log.info("微信企业支付，请求：\n" + reqXml + "，\n返回：\n" + result);
            if (!StringUtil.isBlankOrNull(result)){
                XStream xStream = new XStream(new DomDriver());
                xStream.ignoreUnknownElements();
                xStream.alias("xml", TransferFundResData.class);
                resData = (TransferFundResData) xStream.fromXML(result);
                //log.debug(JSON.toJSON(transferFundReqData));
                return resData;
            }
        } catch (Exception e) {
            log.error("转账失败：请求参数：\n" + reqXml + "\n, 错误信息：" + e.getMessage());
            resData.setResult_code("FAIL");
            resData.setReturn_msg(e.getMessage());
        }
        return resData;
    }

    /**
     * 微信企业付款测试
     */
    public static void main(String[] args) throws IllegalAccessException {
        TransferFundReqData data = new TransferFundReqData();

        data.setMch_appid("wxec7a94ebfb021991"); //wxf45cb3432988261f
        data.setMchid("1361590202"); // 1357152002
        data.setOpenid("oflCGw6V1u3afI-kbKqb2W-yVuC4"); //
        data.setAmount(100);
        //data.setCheck_name("NO_CHECK");
        //data.setRe_user_name("朱春杰");
        data.setPartner_trade_no("100000982014120919631");
        data.setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
        data.setDesc("提现");
        data.setSpbill_create_ip("192.168.1.160");
        String sign = Signature.getSign(data, "DbCHaB3DkMAK5DEqGvMfA78uu5zJpIFT"); //DbCHaB3DkMAK5DEqGvMfA78uu5zJpIFT
        data.setSign(sign);
        data.setSslCertificate(WeichatServiceApi.class.getResourceAsStream("/apiclient_cert.p12"));
        new WeichatServiceApi().transferFund(data);
    }

    /**
     * 设置所属行业
     *
     * @return
     */
    public Map<String, String> setIndustry(String industry1, String industry2, String globalAccessToken, String certLocalPath, String certPassword) throws Exception {
        String url = "https://api.weixin.qq.com/cgi-bin/templates/api_set_industry?access_token=" + globalAccessToken;
        Map<String, String> param = new HashMap<String, String>();
        param.put("industry_id1", industry1);
        param.put("industry_id2", industry2);
        HttpsClientUtil httpsClientUtil = new HttpsClientUtil(certLocalPath, certPassword);
        String result = httpsClientUtil.sendPost(url, JSONObject.fromObject(param).toString(), "text/json");
        Util.log(result);
        return ObjectUtil.convertXmlToMap(result);
    }


    private Map<String, String> getResultToMap(String url) {
        try {
            log.debug("user Access URL ==> " + url);
            String result = HttpClientUtils.get(url);
            log.debug("server result ==> " + result);
            if (StringUtils.isEmpty(result)) {
                return null;
            }
            return stringToMap(result);
        } catch (Exception e) {
            Util.log(e);
        }
        return null;
    }

    private Map<String, String> stringToMap(String result) {
        try {
            JSONObject object = JSONObject.fromObject(result);
            Map<String, String> map = new HashMap<String, String>();
            if (!object.containsKey("errcode")) {
                Iterator<String> keys = object.keySet().iterator();
                while (keys.hasNext()) {
                    String key = keys.next();
                    map.put(key, object.get(key).toString());
                }
                return map;
            }
        } catch (Exception e) {
            log.error(ObjectUtil.getFullStackTraceToString(e));
        }
        return null;
    }

    /**
     * 发送模板信息给用户.
     *
     * @param jsonObject
     * @return
     * @throws Exception
     */
    public String sendUserTemplateMessage(JSONObject jsonObject, String globalAccessToken, String certLocalPath, String certPassword) throws Exception {
        String url = "https://api.weixin.qq.com/cgi-bin/message/templates/send?access_token=" + globalAccessToken;
        HttpsClientUtil httpsClientUtil = new HttpsClientUtil(certLocalPath, certPassword);
        String result = httpsClientUtil.sendPost(url, jsonObject.toString(), "text/json");
        Util.log(result);
        return result;
    }

    public OpenIdAndSessionVo getOpenIdAndSession(String appId, String appdSecret, String jsCode) {
        OpenIdAndSessionVo vo = new OpenIdAndSessionVo();
        String url = String.format("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code", appId, appdSecret, jsCode);
        String responseStr = HttpUtils.sendWebRequestByGet(null, url);
        if (StringUtil.isBlankOrNull(responseStr)) {
            return null;
        }
        vo = GsonUtils.jsonStrToEntity(responseStr, OpenIdAndSessionVo.class);
        return vo;
    }

    public String sendToUserTemplate(String templateId, String url, String toUser, JSONObject jsonObject, String globalAccessToken) {
        TemplateMessageProtocal templateMessageProtocal = new TemplateMessageProtocal();
        templateMessageProtocal.setTouser(toUser);
        templateMessageProtocal.setTemplate_id(templateId);
        templateMessageProtocal.setTopcolor("#173177");
        templateMessageProtocal.setUrl(url);
        templateMessageProtocal.setData(jsonObject);
        try {
            // sendUserTemplateMessage(JSONObject.fromObject(templateMessageProtocal), globalAccessToken);
        } catch (Exception e) {
            Util.log(e);
        }
        return "success";
    }



}
